(function(factory) {
	if(typeof define === 'function' && define.amd) {
		define(['jquery', 'moment', 'math', 'bootstrap.paginator', 'bootstrap.table-cn', 'bootstrap.table.edit',
			'select2-cn', 'xlsx', 'bDialog', 'vw.static', 'vw.edittable.data', 'css!../lib/vw/css/vw.edittable.css'
		], factory);
	} else {
		if(typeof module === 'Object' && module.exports) {
			//
		} else {
			factory(window.jQuery, moment, math);
		}
	}
})(function($, moment, math) {
	'use strict';
	var pluginName = "vw_edittable";
	var defaults = {
		type: "", //table/report
		$container: null,
		height: 20,
		heightDiff: 20,
		editable: false, //是否启用编辑
		showNewData: false,
		showErrorlog: false,
		showEdit: false,
		showDelete: true,
		dataURL: "", //数据内容的接口地址
		saveURL: "", //保存数据的接口地址
		deleteURL: "", //删除数据的接口地址
		idField: "PK_ID", //程序自动添加的主键字段的名称，要确保和其他字段不重复
		defaultEmptyText: "---",
		errorItemColor: "#5bc0de",
		mathErrorColor: "#FF0000",
		columnFormatter: null,
		minYear: 1949,
		maxYear: (new Date()).getFullYear(),
		dateFormat: 'yyyy-mm-dd',
		viewDateFormat: 'YYYY年MM月DD日',
		dateTimeFormat: 'yyyy-mm-dd hh:ii',
		viewDateTimeFormat: "",
		POSITION_SPLIT: ";",
		jsFile: "",
		customFn: "customFn",
		ignoreVisible: false,
		maxRow: 5000,
		extrapara: {}, //额外需要传递的参数
		/*table类型专用*/
		showLoadModel: false,
		showImportData: false,
		showInsertData: false,
		showCheckColumn: true,
		showExport: false,
		modelFile: {
			headerRow: 1, //字段名在哪一行，从1开始
			startRow: 2, //从哪一行开始读表格数据，从1开始
		},
		modelURL: "", //模版数据的接口地址
		submitURL: "", //提交数据的接口地址
		operate: null,
		locate: null,
		ExtraTools: "",
		onInitialized: undefined,
		onDataLoaded: undefined,
		onRowClicked: undefined,
		onRowChecked: undefined,
		onRowUnChecked: undefined,
		onAllEvents: undefined,
		selectRowColor: "#e0ffff",
		/*report类型专用*/
		selectColor: "#CAE1FF",
	};

	var methods = [
		'getOptions',
		'ajaxLoadTableModel',
		'ajaxLoadTableData',
		'ajaxLoadReportData',
		'hasUncommitData',
		'getSelections',
		'excuteJSFunctions',
		'destroy'
	];

	var vw_edittable = function(element, options) {
		this.$element = $(element);
		this.options = $.extend({}, defaults, options);
		this._defaults = defaults;
		this._name = pluginName + this.$element.attr('id');
		this.version = 'v1.0.0';

		this._initData();

		if(this.options.type == "table") {
			this._initTable();
		} else if(this.options.type == "report") {
			this._initReport();
		} else {
			return;
		}
	}

	vw_edittable.prototype = {
		_initData: function() {
			var that = this;

			that.tableData = new tableData(that.options);
			that.columns = that.tableData._columns;
			that.data = that.tableData._data;
			that.errors = that.tableData._errors;
			that.editedCells = that.tableData._editedCells;
			that.p_errors = that.tableData._p_errors;

			that.columns.propertyChange = function(value) {
				if(that.options.type == "table") {
					var index = 0;
					if(that.options.showCheckColumn) {
						that.columns.spliceData(index, {
							field: "-",
							title: "-",
							sortable: false,
							searchable: false,
							checkbox: true
						});
						index++;
					}

					that.columns.spliceData(index, {
						field: that.options.idField,
						title: that.options.idField,
						visible: false,
						sortable: false,
						searchable: false
					});

					that.$table.bootstrapTable('destroy').bootstrapTable({
						"data": [],
						"columns": value,
						"idField": that.options.idField, //固定
						"height": that.height,
						"search": true,
						"searchOnEnterKey": true,
						"pagination": true,
						"pageList": [10, 20, 50, 'All'],
						"showJumpto": true,
						"formatJumpto": function() {
							return '跳转';
						},
						"buttonsClass": "primary",
						"toolbar": that._toolbar,
						"locale": 'zh_CN',
					});

					$(that._toolbar).css('padding-top', "0");
				}
			};

			that.data.propertyChange = function(value) {

				/*检查数据中的错误并进行渲染*/
				that._checkErrors();

				var len = Object.getOwnPropertyNames(value).length; //新增记录数
				if(that.$newnum) {
					that.$newnum.text(len);
				}
				if(that.$fnSubmit) {
					that.$fnSubmit.prop('disabled', !(!that.data.submitted && !that.errors.data.length)); //有新增记录且没有错误记录
				}
			};

			that.errors.propertyChange = function(value) {
				if(that.$errornum) {
					that.$errornum.text(value.length);
				}
				if(that.$fnSubmit) {
					that.$fnSubmit.prop('disabled', !(!that.data.submitted && !value.length)); //有新增记录且没有错误记录
				}
			};

			that.editedCells.propertyChange = function(value) {
				if(that.$editnum) {
					that.$editnum.text(value.length); //已编辑单元格数
				}
				if(that.$fnSave) {
					that.$fnSave.prop('disabled', !value.length); //有已编辑数据
				}
			};

			that.p_errors.propertyChange = function(value) {
				if(value < 0) {
					that.p_errors.data = -1;
				}
				if(value >= that.errors.data.length) {
					that.p_errors.data = that.errors.data.length;
				}
				that._locateToError(that.p_errors.data);
			};
		},

		_initTable: function() {
			var that = this;

			that._appendMaskDiv();

			var HTML_GROUP_LOADMODEL = [
				'<button type="button" id="' + that._name + '-loadmodel" class="btn btn-primary">加载模版</button>',
				'<input type="file" id="' + that._name + '-model" class="hidden" />',
			].join("");

			var HTML_GROUP_LOADDATA_A = [
				'<button type="button" id="' + that._name + '-import" class="btn btn-primary"><i class="fa fa-file-text"></i>  导入</button>',
				'<input type="file" id="' + that._name + '-fileimport" class="hidden" />',
			].join("");

			var HTML_GROUP_LOADDATA_B = [
				'<button type="button" id="' + that._name + '-insert" class="btn btn-primary"><i class="fa fa-file-text-o"></i>  追加</button>',
				'<input type="file" id="' + that._name + '-fileinsert" class="hidden" />',
			].join("");

			var HTML_GROUP_EDIT_A = [
				'<button type="button" id="' + that._name + '-new" class="btn btn-primary"><i class="fa fa-plus"></i>  新增</button>',

			].join("");

			var HTML_GROUP_ERRORLOG = [
				'<div class="btn-group">',
				'	<button type="button" id="' + that._name + '-lasterr" class="btn btn-info"><i class="fa fa-chevron-circle-left"></i></button>',
				'	<button type="button" id="' + that._name + '-errlog" class="btn btn-info">错误',
				'		（<span class="text-danger" id="' + that._name + '-errnum"></span>）' +
				'	</button>',
				'	<button type="button" id="' + that._name + '-nexterr" class="btn btn-info"><i class="fa fa-chevron-circle-right"></i></button>',
				'</div>'
			].join("");

			var HTML_GROUP_SUBMIT = [
				'<button type="button" id="' + that._name + '-submit" class="btn btn-success"><i class="fa fa-cloud-upload"></i>  提交',
				'	（<span style="color:white" id="' + that._name + '-newnum"></span>）' +
				'</button>',
			].join("");

			var HTML_GROUP_EDIT_B = [
				'<button type="button" id="' + that._name + '-save" class="btn btn-warning"><i class="fa fa-save"></i>  保存',
				'	（<span style="color:white" id="' + that._name + '-editnum"></span>）' +
				'</button>',
			].join("");

			var HTML_GROUP_EDIT_C = [
				'<button type="button" id="' + that._name + '-delete" class="btn btn-danger"><i class="fa fa-trash"></i>  删除</button>',
			].join("");

			var HTML_GROUP_EXPORT = [
				'<button type="button" id="' + that._name + '-export" class="btn btn-primary"><i class="fa fa-download"></i>  导出</button>',
			].join("");

			that.$element.empty();

			that.$element.append([
				'<div id="' + that._name + '-toolbar">',
				this.options.showLoadModel ? HTML_GROUP_LOADMODEL : "",
				this.options.showImportData ? HTML_GROUP_LOADDATA_A : "",
				this.options.showInsertData ? HTML_GROUP_LOADDATA_B : "",
				this.options.showNewData ? HTML_GROUP_EDIT_A : "",
				this.options.showErrorlog ? HTML_GROUP_ERRORLOG : "",
				this.options.showImportData || this.options.showInsertData || this.options.showNewData ? HTML_GROUP_SUBMIT : "",
				this.options.showEdit ? HTML_GROUP_EDIT_B : "",
				this.options.showEdit && this.options.showDelete ? HTML_GROUP_EDIT_C : "",
				this.options.showExport ? HTML_GROUP_EXPORT : "",
				this.options.ExtraTools,
				'</div>',
				'<table id="' + that._name + '-table"></table>',
			].join(""));

			if(this.options.showImportData || this.options.showInsertData || this.options.showNewData || this.options.showErrorlog || this.options.showEdit) {
				this.options.editable = true;
			}

			that._toolbar = '#' + that._name + '-toolbar';
			$(that._toolbar).css('padding-top', "10px");
			$(that._toolbar + ' button').css('margin-left', '5px');
			$(that._toolbar + ' .btn-group').css('margin-left', '5px');
			$(that._toolbar + ' .btn-group button').css('margin-left', '0');

			that.$table = $('#' + that._name + '-table');
			that.$fnLoadModel = $('#' + that._name + '-loadmodel');
			that.$model = $('#' + that._name + '-model');
			that.$fnImport = $('#' + that._name + '-import');
			that.$fileImport = $('#' + that._name + '-fileimport');
			that.$fnInsert = $('#' + that._name + '-insert');
			that.$fileInsert = $('#' + that._name + '-fileinsert');
			that.$fnNewTable = $('#' + that._name + '-new');
			that.$fnErrLog = $('#' + that._name + '-errlog');
			that.$errornum = $('#' + that._name + '-errnum');
			that.$fnLastErr = $('#' + that._name + '-lasterr');
			that.$fnNextErr = $('#' + that._name + '-nexterr');
			that.$fnSubmit = $('#' + that._name + '-submit');
			that.$newnum = $('#' + that._name + '-newnum');
			that.$fnSave = $('#' + that._name + '-save');
			that.$editnum = $('#' + that._name + '-editnum');
			that.$fnDelete = $('#' + that._name + '-delete');
			that.$fnExportTable = $('#' + that._name + '-export');

			that.$control = that.$table;

			that.$fnLoadModel.on('click', function() {
				that.$model.click();
			});

			that.$model.on('change', function() {
				that._loadModelfromFile($(this)[0].files[0]);
				this.value = null; //解决无法上传同一文件问题
			});

			that.$fnImport.on('click', function() {
				that._overlap = true;
				that.$fileImport.click();
			});

			that.$fnInsert.on('click', function() {
				that._overlap = false;
				that.$fileInsert.click();
			});

			that.$fileImport.on('change', function() {
				that._loadDataFromFile($(this)[0].files[0]);
				this.value = null;
			});

			that.$fileInsert.on('change', function() {
				that._loadDataFromFile($(this)[0].files[0]);
				this.value = null;
			});

			that.$fnNewTable.on('click', function() {
				that._overlap = false;
				that._newTable();
			});

			that.$fnErrLog.on('click', function() {
				that._errlog();
			});

			that.$fnLastErr.on('click', function() {
				that.p_errors.toPrevious();
			});

			that.$fnNextErr.on('click', function() {
				that.p_errors.toNext();
			});

			that.$fnSubmit.on('click', function() {
				that._submit();
			});

			that.$fnSave.on('click', function() {
				that._saveTable();
			});

			that.$fnDelete.on('click', function() {
				that._deleteTable();
			});

			that.$fnExportTable.on('click', function() {
				that._exportTable();
			});

			that.$table.on('click-row.bs.table', function(e, row, $element, field) {
				var curColor = vw_static.colorRGBtoHex($element.css("background-color"));
				that.$table.find("tr").css("background-color", "");

				if(curColor != that.options.selectRowColor) {
					$element.css("background-color", that.options.selectRowColor);
				}

				that.$element.trigger("onRowClicked", row, $element, field);
				if(that.options.onRowClicked) {
					that.options.onRowClicked.call(that, row, $element, field);
				}
			});

			that.$table.on('check.bs.table', function(e, row, $element) {
				that.$element.trigger("onRowChecked", row, $element);
				if(that.options.onRowChecked) {
					that.options.onRowChecked.call(that, row, $element);
				}
			});

			that.$table.on('uncheck.bs.table', function(e, row, $element) {
				that.$element.trigger("onRowUnChecked", row, $element);
				if(that.options.onRowUnChecked) {
					that.options.onRowUnChecked.call(that, row, $element);
				}
			});

			that.$table.on('editable-save.bs.table', function(e, field, row, oldValue, $el) {
				that._saveEdit(field, row, $el);
				that._clearNextLevel($el);
				resize();
			});

			that.$table.on('all.bs.table', function() {
				that.$fnDelete.prop('disabled', !that.$table.bootstrapTable('getSelections').length);
				that.$element.trigger("onAllEvents");
				if(that.options.onAllEvents) {
					that.options.onAllEvents.call(that);
				}
			});

			that.$table.on('page-change.bs.table', function(e, number, size) {
				that._renderCells();
			});

			resize();
			$(window).resize(resize);

			function resize() {
				var containerHeight;
				if(that.options.$container) {
					containerHeight = that.options.$container.height();
				} else {
					if(that.options.height) {
						containerHeight = that.options.height;
					} else {
						containerHeight = $(window).height();
					}
				}
				that.height = containerHeight - that.options.heightDiff;

				that.$table.bootstrapTable('resetView', {
					//					'width': that.options.$container.width(),
					"height": that.height
				});

				$(".fixed-table-container", that.$element).css('padding-bottom', 40 + "px");
			}

			that.$element.trigger("onInitialized");
			if(that.options.onInitialized) {
				that.options.onInitialized.call(that);
			}
		},

		_initReport: function() {
			var that = this;

			that._appendMaskDiv();

			var HTML_GROUP_EDIT_PAGE = [
				'<button type="button" id="' + that._name + '-new" class="btn btn-primary"><i class="fa fa-plus"></i>  新增页</button>',
				'<button type="button" id="' + that._name + '-delete" class="btn btn-danger"><i class="fa fa-trash"></i>  删除页</button>'
			].join("");

			var HTML_GROUP_EDIT_BYSELECT = [
				'<button type="button" id="' + that._name + '-multi" class="btn btn-primary"><i class="fa fa-bars"></i>  批量填写</button>',
				'<button type="button" id="' + that._name + '-eraser" class="btn btn-warning"><i class="fa fa-eraser"></i>  擦除</button>',
			].join("");

			var HTML_GROUP_ERRORLOG = [
				'<div class="btn-group">',
				'	<button type="button" id="' + that._name + '-lasterr" class="btn btn-info"><i class="fa fa-chevron-circle-left"></i></button>',
				'	<button type="button" id="' + that._name + '-errlog" class="btn btn-info">错误',
				'		（<span class="text-danger" id="' + that._name + '-errnum"></span>）' +
				'	</button>',
				'	<button type="button" id="' + that._name + '-nexterr" class="btn btn-info"><i class="fa fa-chevron-circle-right"></i></button>',
				'</div>'
			].join("");

			var HTML_GROUP_EDIT_SAVE = [
				'<button type="button" id="' + that._name + '-save" class="btn btn-success"><i class="fa fa-save"></i>  保存',
				'	（<span style="color:white" id="' + that._name + '-editnum"></span>）' +
				'</button>',

			].join("");

			that.$element.append([
				'<div class="row">',
				'	<div id="' + that._name + '-toolbar" class="col-md-12">',
				this.options.showNewData ? HTML_GROUP_EDIT_PAGE : "",
				this.options.showEdit ? HTML_GROUP_EDIT_BYSELECT : "",
				this.options.showErrorlog ? HTML_GROUP_ERRORLOG : "",
				this.options.showEdit ? HTML_GROUP_EDIT_SAVE : "",
				'	</div>',
				'</div>',
				'<div class="row">',
				'	<div id="' + that._name + '-frame"></div>',
				'	<ul id="' + that._name + '-framepage" style="margin:0;float:right;"></ul>',
				'</div>'
			].join(""));

			if(this.options.showErrorlog || this.options.showEdit) {
				this.options.editable = true;
			}

			that.$fnNewReport = $('#' + that._name + '-new');
			that.$fnDelete = $('#' + that._name + '-delete');

			that.$fnMulti = $('#' + that._name + '-multi');
			that.$fnEraser = $('#' + that._name + '-eraser');

			that.$fnErrLog = $('#' + that._name + '-errlog');
			that.$errornum = $('#' + that._name + '-errnum');
			that.$fnLastErr = $('#' + that._name + '-lasterr');
			that.$fnNextErr = $('#' + that._name + '-nexterr');

			that.$fnSave = $('#' + that._name + '-save');
			that.$editnum = $('#' + that._name + '-editnum');

			that.$element.css('padding-right', '15px');

			that.$frame = $('#' + that._name + '-frame');
			that.$framepage = $('#' + that._name + '-framepage');
			that.$frame.css({
				'width': '98%',
				'overflow-y': 'auto',
				"display": "-webkit-flex",
				"-webkit-justify-content": "center",
				"margin": "10px 20px"
			});

			that.$control = that.$frame;

			that._toolbar = '#' + that._name + '-toolbar';
			$(that._toolbar).css('padding-top', "10px");
			$(that._toolbar + ' button').css('margin-left', '5px');
			$(that._toolbar + ' .btn-group').css('margin-left', '5px');
			$(that._toolbar + ' .btn-group button').css('margin-left', '0');

			that.$framepage.bootstrapPaginator({
				bootstrapMajorVersion: 3,
				currentPage: 1,
				numberOfPages: 5,
				totalPages: 1,
				shouldShowPage: true,
				useBootstrapTooltip: true,
				onPageClicked: function(event, originalEvent, type, page) {
					that._readReportDataPerPage(page);
				}
			});

			that.$fnNewReport.on('click', function() {
				that._overlap = false;
				that._newReport();
			});

			that.$fnDelete.on('click', function() {
				that._deleteReport();
			});

			that.$fnMulti.on('click', function() {
				that._multi();
			});

			that.$fnEraser.on('click', function() {
				that._eraser();
			});

			that.$fnErrLog.on('click', function() {
				that._errlog();
			});

			that.$fnLastErr.on('click', function() {
				that.p_errors.toPrevious();
			});

			that.$fnNextErr.on('click', function() {
				that.p_errors.toNext();
			});

			that.$fnSave.on('click', function() {
				that._saveReport();
			});

			that._selectCell();
			that.$fnMulti.prop('disabled', true);
			that.$fnEraser.prop('disabled', true);
			//			that.$fnSave.prop('disabled', true);

			resize();
			$(window).resize(resize);

			function resize() {
				var containerHeight;
				if(that.options.$container) {
					containerHeight = that.options.$container.height();
				} else {
					if(that.options.height) {
						containerHeight = that.options.height;
					} else {
						containerHeight = $(window).height();
					}
				}

				that.height = containerHeight - that.options.heightDiff - 115;

				that.$frame.css('height', that.height + "px");
			}
		},

		_appendMaskDiv: function() {
			var that = this;

			var HTML_PROGRESS = [
				'<div id="vw-progress" class="list-item hidden">',
				'	<div class="p-icon">',
				'		<i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i>',
				'	</div>',
				'	<div id="vw-progress-text"></div>',
				'	<button type="button" id="btn-cancel-progress" class="btn btn-danger"><i class="fa fa-remove"></i>  取消</button>',
				//'	<div id="vw-progress-remark">（若进度刷新延迟，手动点击页面任意位置可刷新）</div>',
				'</div>'
			].join("");

			$("body").append(HTML_PROGRESS);

			$("#vw-progress").css({
				"position": "fixed",
				"top": 0,
				"left": 0,
				"width": "100%",
				"height": "100%",
				"background": "#FFFFFF",
				"z-index": 15000,
				"filter": "alpha(opacity:80)",
				"opacity": 0.8,
				"moz-opacity": 0.8,
				"khtml-opacity": 0.8
			});

			$("#vw-progress .p-icon").css({
				"position": "absolute",
				"top": "40%",
				"left": "50%",
				"width": "64px",
				"height": "64px",
				"margin-top": "-32px",
				"margin-left": "-32px"
			});

			$("#vw-progress-text").css({
				"position": "absolute",
				"top": "45%",
				"left": "27%",
				"font-size": "24px"
			});

			$("#vw-progress-remark").css({
				"position": "absolute",
				"top": "65%",
				"left": "33%",
				"font-size": "18px"
			});

			$('#btn-cancel-progress').css({
				"position": "absolute",
				"top": "55%",
				"left": "47%"
			}).on('click', function() {
				$("#vw-progress").addClass('hidden');
				if(that.worker) {
					that.worker.terminate();
				}
			})
		},

		destroy: function() {
			this.$element.empty();
			this.tableData = null;
		},

		getOptions: function() {
			return this.options;
		},

		getSelections: function() {
			if(this.options.type == "table") {
				return this.$table.bootstrapTable('getSelections');
			} else if(this.options.type == "report") {
				return null;
			}
		},

		excuteJSFunctions: function(fn, paras) {
			var that = this;
			if(that.options.jsFile) {
				$.getScript(that.options.jsFile, function() {
					if(typeof window[that.options.customFn] != 'undefined' && typeof window[that.options.customFn][fn] != 'undefined') {
						eval(that.options.customFn + "[fn](paras)");
					}
				});
			}
			/*js文件格式形如:
			var customFn = function() {
				return {
					ConLog: function(para) {
						console.log(para)
					}
				}
			}();
			其中：“customFn”、“ConLog”均可自定义。
			调用方式：
			1、vw_edittable的options：jsFile(js文件全路径)、customFn（js文件中函数名称、默认为"customFn"）
			2、$element.vw_edittable（"excuteJSFunctions",js中方法名,参数）执行该函数;
			*/
		},

		hasUncommitData: function() {
			var that = this;
			return !that.data.submitted || that.editedCells.data.length;
		},

		_loadModelfromFile: function(selectedFile) {
			var that = this;
			openFileDialog(selectedFile, function(workbook, sheetname) {
				that.columns.setData(XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[sheetname]]));
			})
		},

		_loadDataFromFile: function(selectedFile) {
			var that = this;
			openFileDialog(selectedFile, function(workbook, sheetname) {
				var sheet = workbook.Sheets[workbook.SheetNames[sheetname]];
				var extent = sheet["!ref"].split(":");
				var rowNum = extent[1].replace(/[^0-9]/ig, "") - extent[0].replace(/[^0-9]/ig, "") + 1 - (that.options.modelFile.startRow - 1);
				var colNum = extent[1].replace(/[0-9]/ig, "").charCodeAt() - extent[0].replace(/[0-9]/ig, "").charCodeAt() + 1;

				if(that.options.maxRow && that.options.maxRow != -1 && rowNum > that.options.maxRow) {
					$("#vw-progress").addClass('hidden');
					$.Notify({
						caption: "提示",
						content: "当前导入数据量过大（超过" + that.options.maxRow + "行），不支持导入",
						type: "warning"
					});
					return;
				}

				var hasValue = false;
				$.each(sheet, function(key, val) {
					var row = key.replace(/[^0-9]/ig, "");
					if(row >= that.options.modelFile.startRow) {
						hasValue = true;
						return false;
					}
				});

				if(!hasValue) {
					$("#vw-progress").addClass('hidden');
					$.Notify({
						caption: "提示",
						content: "当前导入数据为空表",
						type: "warning"
					});
					return;
				}

				//读表头
				var columns = {},
					cols = [];
				$.each(sheet, function(key, val) {
					var row = key.replace(/[^0-9]/ig, "");
					if(row == that.options.modelFile.headerRow) {
						var col = key.replace(/[0-9]/ig, "");
						columns[col] = val.v;
						cols.push({
							title: val.v,
							cannull: 1
						});
					}
				});

				if(!that.columns.data.length) {
					that.columns.setData(cols);
				}

				//读表体
				var json = [];
				for(var i = 0; i < rowNum; i++) {
					json[i] = {};
				}

				$.each(sheet, function(key, val) {
					var row = key.replace(/[^0-9]/ig, "");
					if(row >= that.options.modelFile.startRow) {
						var col = key.replace(/[0-9]/ig, "");
						if(val.t == "d") {
							json[row - that.options.modelFile.startRow][columns[col]] = moment(val.v).format("YYYY-MM-DD HH:mm:ss");
						} else {
							json[row - that.options.modelFile.startRow][columns[col]] = val.v;
							for(var k in that.columns.colSource) {
								if(columns[col] == k) {
									for(var i in that.columns.colSource[k]) {
										if(val.v == that.columns.colSource[k][i]) {
											json[row - that.options.modelFile.startRow][columns[col]] = i;
											return true;
										}
									}
								}
							}
						}
					}
				});

				for(var i = json.length - 1; i >= 0; i--) {
					if(!Object.getOwnPropertyNames(json[i]).length) {
						json.splice(i, 1);
					}
				}

				that._loadToTable(json, false);
			})
		},

		ajaxLoadTableModel: function(table) {
			var that = this;
			if(that.options.type != "table") {
				console.error("options.type != table");
				return;
			}
			if(!that.options.modelURL || !table) {
				return;
			}
			that._tableid = table;
			that.options.extrapara.table = that._tableid;

			vw_common.customAjax({
				url: that.options.modelURL,
				type: "GET",
				dataType: "json",
				data: that.options.extrapara
			}, function(e) {
				that.columns.setData(e.columns);
			});
		},

		ajaxLoadTableData: function(table, tableName, menutype) {
			var that = this;
			if(that.options.type != "table") {
				console.error("options.type != table");
				return;
			}

			if(!that.options.dataURL || !table) {
				return;
			}

			$("#vw-progress-text").html('正在向服务器请求数据，数据量较大，加载时间视数据量及网络状况...');
			$("#vw-progress").removeClass('hidden');

			that._tableid = table;
			that._tableName = tableName;
			that._overlap = true;

			that.options.extrapara.type = menutype;
			that.options.extrapara.table = that._tableid;

			vw_common.customAjax({
				url: that.options.dataURL,
				type: "GET",
				dataType: "json",
				data: that.options.extrapara
			}, function(e) {
				/*构造表头*/
				that.columns.setData(e.columns);

				if(e.wholedata && e.data.length < e.wholedata) {
					$.Notify({
						caption: "提示",
						content: "该数据记录数过多，只加载(" + e.data.length + "/" + e.wholedata + ")行记录",
						type: "warning"
					});
				}

				/*未启用编辑时进行翻译，显示枚举的Text，而不是value*/
				if(!that.options.editable) {
					$.each(e.data, function(i, row) {
						for(var k in that.columns.colSource) {
							var row_split = row[k].split(',');
							if(row_split && row_split.length == 1) {
								row[k] = that.columns.colSource[k][row[k]];
							} else {
								var vals = [];
								$.each(row_split, function(j, val) {
									vals.push(that.columns.colSource[k][val]);
								});
								row[k] = vals.join(',');
							}
						};
					});
				} else {
					/*翻译disable类型字段中的枚举值*/
					var disabledCols = [];
					$.each(that.columns.data, function(k, val) {
						if(val.disable) {
							disabledCols.push(val.title);
						}
					});

					$.each(e.data, function(i, row) {
						$.each(row, function(key, attrVal) {
							if(disabledCols.indexOf(key) != -1 && that.columns.colSource[key]) {
								var row_split = attrVal.split(',');
								if(row_split && row_split.length == 1) {
									row[key] = that.columns.colSource[key][attrVal];
								} else {
									var vals = [];
									$.each(row_split, function(j, val) {
										vals.push(that.columns.colSource[key][val]);
									});
									row[key] = vals.join(',');
								}
							}
						});
					});
				}

				/*构造表体*/
				that._loadToTable(e.data, true);
			}, function() {
				$("#vw-progress").addClass('hidden');
			});
		},

		_startUniqueID: function() {
			return Number(new Date()) * 1000;
		},

		_loadToTable: function(json, submit) {
			var that = this;

			/*给数据增加checkbox和主键字段内容*/
			var startID = that._startUniqueID();
			var count = 0;
			$.each(json, function(k, val) {
				if(that.options.showCheckColumn) {
					val["-"] = "";
				}
				if(!val[that.options.idField]) {
					val[that.options.idField] = startID + count;
					count++;
				}
			});

			/*构造数据并向table中填充*/
			var copyData = [];
			if(that._overlap) {
				that.data.setData(json, submit);
				$.extend(true, copyData, that.data.allData);
				that.$table.bootstrapTable('load', copyData);
			} else {
				that.data.insertData(json);
				$.extend(true, copyData, that.data.allData);
				that.$table.bootstrapTable('append', copyData);
			}

			/*触发onDataLoaded事件*/
			var eventData = {
				columns: that.columns.oriData,
				pk: that.options.idField,
				data: that.data.allData
			};
			that.$element.trigger("onDataLoaded", eventData);
			if(that.options.onDataLoaded) {
				that.options.onDataLoaded.call(that, eventData);
			}
		},

		ajaxLoadReportData: function(htmlFile, table, tableName, menutype) {
			var that = this;
			if(that.options.type != "report") {
				console.error("options.type != report");
				return;
			}

			if(!that.options.dataURL || !table || !htmlFile) {
				return;
			}

			that.$frame.load(htmlFile, function(response, status) {
				if(status != "success") {
					$.Notify({
						caption: "错误",
						content: "表单文件（" + htmlFile + "）加载失败",
						type: "alert"
					});
					return;
				}

				that.$frame.find('table').css({
					'width': '99%'
				});

				that.$frame.find('td a').each(function() {
					var oldID = $(this).parent().attr("id");
					$(this).parent().attr("id", vw_static.idToPosition(oldID));
					$(this).parent().attr("align", "center");
				});

				/*触发保存的事件，并处理表头数据*/
				that.$frame.find('td a').off('save').on('save', function(e, params) {
					var col = $(e.currentTarget).attr('data-name');
					var row = {};
					$.each(that.data.allData, function(k, val) {
						if(val[that.options.idField] == $(e.currentTarget).attr('data-pk')) {
							row = val;
							row[col] = params.newValue;
							pharseReportHeader(params.newValue, col);
							return true;
						}
					});
					that._saveEdit(col, row, $(e.currentTarget));
					that._clearNextLevel($(this));
				});

				/*填充报表*/

				that._tableid = table;
				that._tableName = tableName;
				that._overlap = true;

				that.options.extrapara.type = menutype;
				that.options.extrapara.table = that._tableid;

				vw_common.customAjax({
					url: that.options.dataURL,
					type: "GET",
					dataType: "json",
					data: that.options.extrapara
				}, function(e) {
					that.columns.setData(e.columns);
					that.data.setData(e.data, true);

					if(e.wholedata && e.data.length < e.wholedata) {
						$.Notify({
							caption: "提示",
							content: "该数据记录数过多，只加载(" + e.data.length + "/" + e.wholedata + ")行记录",
							type: "warning"
						});
					}

					that._recordsPerPage = e.pageCount;
					that.$framepage.bootstrapPaginator('setOptions', {
						totalPages: Math.ceil(that.data.allData.length / that._recordsPerPage)
					});
					if(that.data.allData.length == 0) {
						$.Notify({
							caption: "提示",
							content: "当前表为空表，请增加新页",
							type: "warning"
						});
					} else {
						that._readReportDataPerPage(1);
					}
				});
			});

			function pharseReportHeader(editedVal, editedCol) {
				$.each(that.data.allData, function(i, row) {
					row[editedCol] = editedVal;

					var dbField = "";
					$.each(that.columns.data, function(k, val) {
						if(val.field == editedCol) {
							dbField = val.name;
							return true;
						}
					});

					var isExist = false;
					$.each(that.editedCells.additionData, function(j, item) {
						if(item.F_ID == row[that.options.idField] && item.F_TEXT == editedCol) {
							item.F_VALUE = editedVal;
							isExist = true;
							return true;
						}
					});
					if(!isExist) {
						that.editedCells.additionData.push({
							F_TEXT: editedCol,
							F_CODE: dbField,
							F_VALUE: editedVal,
							F_ID: row[that.options.idField]
						});
					}
				});
			}
		},

		_readReportDataPerPage: function(page) {
			var that = this;
			that.$frame.find('td a')
				.text("")
				.removeClass("vw-CheckError")
				.removeClass("vw-CheckEdited");

			var startID = that._startUniqueID();
			var count = 0;
			$.each(that.columns.data, function(key, val) {
				if(!val.cellposition) {
					return;
				}
				var range = val.cellposition.split(that.options.POSITION_SPLIT);

				for(var i = 0; i < range.length; i++) {
					var $item = that.$frame.find('#' + range[i] + ' a');
					$item.editable('destroy').editable(val.editable);
					$item.attr('data-name', val.field);
					var cellData = that.data.allData[i + that._recordsPerPage * (page - 1)];
					if(cellData) {
						$item.editable('setValue', cellData[val.field]);
						$item.attr('data-pk', cellData[that.options.idField] + "");
						for(var ec in that.editedCells.data) {
							if($item.attr('data-pk') == that.editedCells.data[ec].F_ID && $item.attr('data-name') == that.editedCells.data[ec].F_TEXT) {
								$item.addClass("vw-CheckEdited");
							}
						}
					} else {
						count++;
						$item.attr('data-pk', startID + count);
					}

					if(!that.options.editable) {
						that.$control.find('.editable').editable('disable');
					}
				}
			});
			that._renderCells();
		},

		/*渲染错误、已编辑、tooltip*/
		_renderCells: function() {
			var that = this;
			$.each(that.$control.find('.editable'), function(key, val) {
				var col = $(val).attr('data-name');
				var row = $(val).attr('data-pk');

				var msg = "";
				$.each(that.errors.data, function(i, cell) {
					if(cell.col == col && cell.row == row) {
						$(val).addClass('vw-CheckError');
						msg = cell.msg;
						return true;
					}
				});

				$.each(that.editedCells.data, function(i, cell) {
					if(cell.F_TEXT == col && cell.F_ID == row) {
						$(val).addClass('vw-CheckEdited');
						return true;
					}
				});

				that._addTooltip($(val), msg);
			});

			/*select类型实现级联选择*/
			that.$control.find('.editable').off('shown').on('shown', function(e, editable) {
				that._linkSelect(editable, this);
			});
		},

		/*多线程，检查错误数据*/
		_checkErrors: function() {
			var that = this;
			var retdata = [];

			that.errors.resetData(true);

			if(!that.data.allData.length) {
				$("#vw-progress").addClass('hidden');
				return;
			}

			if(!that.options.editable) {
				return;
			}

			that.worker = new Worker('lib/vw/js/worker.js');
			that.worker.postMessage({
				data: that.data.allData,
				columns: that.columns.oriData,
				source: that.columns.colSource,
				idField: that.options.idField,
			});

			that.worker.addEventListener("message", function(e) {
				$("#vw-progress-text").html('数据读取完毕，正在对第  <span  style="color:red">' + e.data.id + '/' + that.data.allData.length + '</span> 条数据进行错误检查，请稍候...');

				if(e.data.data) {
					retdata.push(e.data.data);
				} else {
					if(e.data.id == that.data.allData.length - 1) {
						that.worker.terminate();
						that.errors.pushDatas(retdata);
						$("#vw-progress").addClass('hidden');
						that._renderCells();
					}
				}
			})
		},

		_saveEdit: function(field, row, $el) {
			var that = this;
			that.data.pushData(row);
			$el.removeClass("vw-CheckError").addClass("vw-CheckEdited");

			var dbField = "";
			$.each(that.columns.data, function(k, val) {
				if(val.field == field) {
					dbField = val.name;
					return false;
				}
			});
			that.editedCells.pushData({
				F_TEXT: field,
				F_CODE: dbField,
				F_VALUE: row[field],
				F_ID: row[that.options.idField]
			});

			that.errors.removeData(row[that.options.idField], field);

			if(that.options.type == "report") {
				that._reportMathCalculate(field, row, $el);
			} else if(that.options.type == "table") {
				that._tableMathCalculate(field, row, $el);
			}
		},

		_newTable: function() {
			var that = this;
			if(!that.columns.data || !that.columns.data.length) {
				$.Notify({
					caption: "提示",
					content: "请先加载模版",
					type: "warning"
				});
				return;
			}

			that.$table.bootstrapTable('selectPage', that.$table.bootstrapTable('getOptions').totalPages);

			var newRow = {};
			var startID = that._startUniqueID();
			$.each(that.columns.data, function(key, val) {
				if(val.field == that.options.idField) {
					newRow[val.field] = startID + key; //vw_static.generateUUID();
				} else {
					newRow[val.title] = val.defaultValue;
				}
			});

			that.$table.bootstrapTable('insertRow', {
				index: that.$table.bootstrapTable('getData').length,
				row: newRow
			});

			that.data.pushData(newRow);

			/*select类型实现级联选择*/
			that.$control.find('.editable').off('shown').on('shown', function(e, editable) {
				that._linkSelect(editable, this);
			});
		},

		_newReport: function() {
			var that = this;
			var page = that.$framepage.bootstrapPaginator('getPages').total + 1;
			var startID = that._startUniqueID();
			for(var i = 0; i < that._recordsPerPage; i++) {
				var newitem = {};
				if(i == 0) {
					$.each(that.$frame.find('.editable'), function(k, el) {
						$.each(that.columns.data, function(k, val) {
							if(val.field == $(el).attr('data-name')) {
								if(val.cellposition && val.cellposition.split(that.options.POSITION_SPLIT).length == 1) {
									var thisText = $(el).text();
									if(thisText != that.options.defaultEmptyText) {
										newitem[val.title] = thisText;
									}
								}
								return true;
							}
						});
					});
				}
				newitem[that.options.idField] = startID + i; //vw_static.generateUUID();
				that.data.pushData(newitem);
			}

			that._submit(function() {
				that.$framepage.bootstrapPaginator('setOptions', {
					totalPages: page
				});
				that.$framepage.bootstrapPaginator('show', page);
				that._readReportDataPerPage(page);
			});

		},

		_saveTable: function() {
			var that = this;
			if(!that.options.saveURL || !that._tableid) {
				return;
			}

			bDialog.alert('确认保存这些数据吗？', function() {

				var ajaxData = {};
				that.options.extrapara.table = that._tableid;
				$.extend(true, ajaxData, that.options.extrapara);
				ajaxData.data = JSON.stringify({
					data: that.editedCells.data
				});

				vw_common.customAjax({
					url: that.options.saveURL,
					type: "POST",
					dataType: "json",
					data: ajaxData
				}, function(e) {
					that.editedCells.resetData();
					that.$table.find('.editable').removeClass("vw-CheckEdited");

					$.Notify({
						caption: "成功",
						content: "数据保存成功",
						type: "success"
					});

				});
			}, {
				messageType: 'confirm',
				cancel: function() {}
			});
		},

		_saveReport: function() {
			var that = this;
			if(!that.options.saveURL || !that._tableid) {
				return;
			}

			bDialog.alert('确认保存这些数据吗？', function() {
				var subData = [];
				$.extend(true, subData, that.editedCells.data);
				$.each(that.editedCells.additionData, function(k, val) {
					var isExist = false;
					$.each(subData, function(j, item) {
						if(item.F_ID == val.F_ID && item.F_TEXT == val.F_TEXT && item.F_VALUE == val.F_VALUE) {
							isExist = true;
							return true;
						}
					});
					if(!isExist) {
						subData.push(val);
					}
				});

				var ajaxData = {};
				that.options.extrapara.table = that._tableid;
				$.extend(true, ajaxData, that.options.extrapara);
				ajaxData.data = JSON.stringify({
					data: subData
				});

				vw_common.customAjax({
					url: that.options.saveURL,
					type: "POST",
					dataType: "json",
					data: ajaxData
				}, function(e) {
					that.editedCells.resetData();
					that.$frame.find('.editable').removeClass("vw-CheckEdited");

					$.Notify({
						caption: "成功",
						content: "数据保存成功",
						type: "success"
					});
				});
			}, {
				messageType: 'confirm',
				cancel: function() {}
			});
		},

		_submit: function(callback) {
			var that = this;
			if(!that.options.submitURL || !that._tableid) {
				return;
			}

			$("#vw-progress-text").html('正在向服务器提交数据， 请耐心等待...');
			$("#vw-progress").removeClass('hidden');

			var ajaxData = {};
			that.options.extrapara.table = that._tableid;
			$.extend(true, ajaxData, that.options.extrapara);

			var submitDataVisible = {}
			$.extend(true, submitDataVisible, that.data.submitData);
			$.each(that.columns.data, function(k, col) {
				if(!col.visible && col.title != that.options.idField) {
					$.each(submitDataVisible, function(i, val) {
						delete val[col.title];
					});
				}
			});
			ajaxData.data = JSON.stringify(submitDataVisible);

			ajaxData.delold = that._overlap;

			vw_common.customAjax({
				url: that.options.submitURL,
				type: "POST",
				dataType: "json",
				data: ajaxData
			}, function(e) {
				that.data.doSubmit();

				if(callback) {
					callback();
				}

				$.Notify({
					caption: "成功",
					content: "数据提交成功",
					type: "success"
				});
			}, null, function() {
				$("#vw-progress").addClass('hidden');
			});
		},

		_deleteTable: function() {
			var that = this;
			if(!that.options.deleteURL || !that._tableid) {
				return;
			}

			var ids = $.map(that.$table.bootstrapTable('getSelections'), function(row) {
				return row[that.options.idField];
			});

			that._deleteRequest(ids, function() {
				that.$table.bootstrapTable('remove', {
					field: that.options.idField,
					values: ids
				});
			}, '确认删除选中的数据吗？删除后将无法恢复！');
		},

		_deleteReport: function() {
			var that = this;
			if(!that.options.deleteURL || !that._tableid) {
				return;
			}

			var page = that.$framepage.bootstrapPaginator('getPages');

			if(page.total == 0) {
				return;
			}

			var ids = [];
			$.each(that.$frame.find('.editable'), function(k, val) {
				if($(val).attr('data-pk')) {
					ids.push($(val).attr('data-pk'));
				}
			});

			that._deleteRequest(vw_static.getUniqueList(ids), function() {

				that.$framepage.bootstrapPaginator('setOptions', {
					totalPages: page.total - 1
				});
				page = that.$framepage.bootstrapPaginator('getPages');
				if(page.total > 0) {
					var targerPage = page.total > page.current ? page.current : page.total;
					that.$framepage.bootstrapPaginator('show', targerPage);
					that._readReportDataPerPage(targerPage);
				} else {
					that.$frame.find('.editable')
						.text("")
						.removeClass("vw-CheckError")
						.removeClass("vw-CheckEdited");

					$.Notify({
						caption: "提示",
						content: "当前表为空表，请增加新页",
						type: "warning"
					});
				}
			}, '确认删除当前页的数据吗？删除后将无法恢复！');
		},

		_deleteRequest: function(ids, fn, text) {
			var that = this;
			bDialog.alert(text, function() {

				var ajaxData = {};
				that.options.extrapara.table = that._tableid;
				$.extend(true, ajaxData, that.options.extrapara);
				ajaxData.ids = JSON.stringify(ids);

				vw_common.customAjax({
					url: that.options.deleteURL,
					type: "GET",
					dataType: "json",
					data: ajaxData
				}, function(e) {

					$.each(ids, function(k, val) {
						that.errors.removeData(Number(val));
						that.editedCells.spliceData(Number(val));
						that.data.removeData(Number(val));
					});

					fn();

					$.Notify({
						caption: "成功",
						content: "数据删除成功",
						type: "success"
					});
				});
			}, {
				messageType: 'confirm',
				cancel: function() {}
			});
		},

		/*级联选择*/
		_linkSelect: function(editable, element) {
			if(editable.input.type == "select" || editable.input.type == "select2") {
				var that = this;
				var dataName = $(element).attr('data-name');
				var row = $(element).attr('data-pk');
				var curCol;
				$.each(that.columns.data, function(k, col) {
					if(dataName == col.title) {
						curCol = col;
					}
				});

				if(!curCol.previouslink) {
					return;
				}

				var upLevel = that.columns.colSource[curCol.previouslink];
				var upLevelText = that.$control.find('a[data-name="' + curCol.previouslink + '"][data-pk="' + row + '"]').text();
				var upLevelVal;
				$.each(upLevel, function(v, t) {
					if(t == upLevelText) {
						upLevelVal = v;
						return false;
					}
				});

				var curVal = editable.value;
				if(editable.input.type == "select") {
					editable.input.$input.empty();
					if(upLevelVal) {
						$.each(curCol.source, function(i, item) {
							if(item.pid == upLevelVal) {
								editable.input.$input.append("<option value='" + item.id + "'>" + item.text + "</option>");
							}
						});
					}
					editable.input.$input.val(curVal);
				} else if(editable.input.type == "select2") {
					var thisSource = [];
					if(upLevelVal) {
						$.each(curCol.source, function(i, item) {
							if(item.pid == upLevelVal) {
								thisSource.push({
									id: item.id,
									text: item.text
								});
							}
						});
					}
					editable.input.$input.select2({
						data: thisSource,
						placeholder: '请选择或输入关键字...',
						allowClear: true,
						minimumInputLength: 1,
						multiple: true
					}).val(curVal).trigger('change');
				}
			}
		},

		_clearNextLevel: function($element) {
			var that = this;
			var dataName = $element.attr('data-name');
			var row = $element.attr('data-pk');
			var curCol;
			$.each(that.columns.data, function(k, col) {
				if(dataName == col.title) {
					curCol = col;
				}
			});

			findNextSelect(curCol);

			function findNextSelect(column) {
				if(!column.nextlink) {
					return;
				}

				var nextlinks = column.nextlink.split(',');
				$.each(nextlinks, function(i, link) {
					var $nextLevel = that.$control.find('a[data-name="' + link + '"][data-pk="' + row + '"]');
					$nextLevel.editable('setValue', column.emptytext ? column.emptytext : that.options.defaultEmptyText);

					$.each(that.columns.data, function(k, datarow) {
						if(datarow.field == link) {
							that.editedCells.pushData({
								F_TEXT: link,
								F_CODE: datarow.name,
								F_VALUE: null,
								F_ID: row
							});
							return true;
						}
					});

					$.each(that.columns.data, function(k, col) {
						if(link == col.title) {
							findNextSelect(col);
							return true;
						}
					});
				});
			}
		},

		_addTooltip: function($target, msg) {
			if(msg) {
				$target.tooltip({
					title: msg
				});
			} else {
				$target.tooltip('destroy')
			}
		},

		_reportMathCalculate: function(field, row, $el) {
			var that = this;
			if(!that.columns.colMath.length) {
				return;
			}
			var curCell = that.$frame.find('td a[data-name="' + field + '"][data-pk="' + row[that.options.idField] + '"]').parent().attr('id');
			var scope = {};
			$.each(that.columns.colMath, function(k, val) {
				if(val.scope.indexOf(curCell) != -1) {
					if(val.type == "=" && curCell == val.target) {
						return;
					}

					for(var i = 0; i < val.scope.length; i++) {
						var $a = that.$frame.find('#' + val.scope[i] + ' a');console.log($a[0])
						if($a.hasClass('vw-CheckEdited')) {
							var v = row[$a.attr('data-name')];
							scope[val.scope[i]] = v ? v : 0;
						} else {
							var v = $a.editable('getValue', true);
							scope[val.scope[i]] = v ? v : 0;
						}
					};

					var ret = math.eval(val.expr, scope);
					var $target = that.$frame.find('#' + val.target + ' a');

					if(ret === true) {
						that._addTooltip($target, "");
					} else if(ret === false) {
						that._addTooltip($target, val.text);
						that.errors.pushDatas([{
							id: that.errors.data.length,
							row: $target.attr('data-pk'),
							col: $target.attr('data-name'),
							val: scope[val.target],
							msg: val.text
						}]);
						that.editedCells.spliceData($target.attr('data-pk'), $target.attr('data-name'));
						that.data.spliceData($target.attr('data-pk'), $target.attr('data-name'), scope[val.target]);
					} else {
						$target.editable('setValue', scope[val.target]);
						$.each(that.data.allData, function(k, v) {
							if(v[that.options.idField] == $target.attr('data-pk')) {
								row = v;
								row[$target.attr('data-name')] = scope[val.target] + "";
								return true;
							}
						});
						that._saveEdit($target.attr('data-name'), row, $target);
					}
				}
			});
		},

		_tableMathCalculate: function(curCol, row, $el) {
			var that = this;
			if(!that.columns.colMath.length) {
				return;
			}
		},

		_selectCell: function() {
			var that = this;
			that.$frame.off('mousedown');
			that.$frame.mousedown(function(e) {
				var startX = e.pageX;
				var startY = e.pageY;
				that._selCells = [];
				var lastCol = "",
					curCol = "";

				that.$frame.mousemove(function(e) {
					var extentSel = {
						left: math.min(e.pageX, startX),
						top: math.min(e.pageY, startY),
						width: math.abs(e.pageX - startX),
						height: math.abs(e.pageY - startY)
					}

					that._selCells = [];
					that.$frame.find('.editable').each(function() {
						var $td = $(this).parent('td');
						var extentCell = {
							left: $td.offset().left,
							top: $td.offset().top,
							width: $td.width(),
							height: $td.height()
						}

						if(vw_static.isIntersect(extentSel, extentCell)) {
							var colName = $(this).attr('data-name');
							var pos = that.$frame.find('td a[data-name="' + colName + '"][data-pk="' + $(this).attr('data-pk') + '"]').parent().attr('id');
							$.each(that.columns.data, function(k, val) {
								if(val.cellposition.indexOf(pos) != -1) {
									that._selColumn = val;
									curCol = colName;
									if(lastCol == "") {
										lastCol = curCol;
									}
								}
							});
							if(lastCol != curCol) {
								$.each(that._selCells, function(k, val) {
									that.$frame.find('td[id=' + val + ']').css('background-color', "");
								});
								that._selCells = [];
								lastCol = curCol;
								startX = e.pageX;
								startY = e.pageY;
							}
							that._selCells.push($td.attr('id'));
							$td.css('background-color', that.options.selectColor);
						} else {
							$td.css('background-color', "");
						}
					});
				});

				that.$frame.mouseup(function(e) {
					if(startX == e.pageX && startY == e.pageY) {
						that.$frame.find('.editable').each(function() {
							var $td = $(this).parent('td');
							var extentCell = {
								left: $td.offset().left,
								top: $td.offset().top,
								width: $td.width(),
								height: $td.height()
							}
							var a1 = e.pageX >= extentCell.left && e.pageX <= extentCell.left + extentCell.width;
							var a2 = e.pageY >= extentCell.top && e.pageY <= extentCell.top + extentCell.height;
							if(a1 && a2) {
								var colName = $(this).attr('data-name');
								var pos = that.$frame.find('td a[data-name="' + colName + '"][data-pk="' + $(this).attr('data-pk') + '"]').parent().attr('id')
								$.each(that.columns.data, function(k, val) {
									if(val.cellposition.indexOf(pos) != -1) {
										that._selColumn = val;
										curCol = colName;
										if(lastCol == "") {
											lastCol = curCol;
										}
									}
								});
								if(lastCol != curCol) {
									$.each(that._selCells, function(k, val) {
										that.$frame.find('td[id=' + val + ']').css('background-color', "");
									});
									that._selCells = [];
									lastCol = curCol;
								}
								$td.css('background-color', that.options.selectColor);
								that._selCells.push($td.attr('id'));
							} else {
								$td.css('background-color', "");
							}
						});
					}

					that.$frame.off('mousemove');
					that.$frame.off('mouseup');
					that.$fnMulti.prop('disabled', !that._selCells.length);
					that.$fnEraser.prop('disabled', !that._selCells.length);
				});
			});
		},

		_multi: function() {
			var that = this;
			var successed = false;
			var newValue = "";
			bDialog.open({
				title: '批量填写',
				dom: '<div style="margin:10px">请输入：</div><a style="margin-left:30px" id="multi_edit"></a>',
				dialogMaxButton: false,
				customClass: 'blue',
				width: 400,
				height: 200,
				fnButton: true,
				fnButtonName: "保存",
				fn: function() {
					if(successed) {
						$.each(that._selCells, function(k, val) {
							var $el = that.$frame.find('td[id=' + val + '] a');
							var col = $el.attr('data-name');
							var row = {};
							$.each(that.data.allData, function(k, val) {
								if(val[that.options.idField] == $el.attr('data-pk')) {
									row = val;
									row[col] = newValue;
									return true;
								}
							});
							$el.editable('setValue', newValue);
							that._saveEdit(col, row, $el);
						});
						bDialog.close();
					} else {
						$.Notify({
							caption: "错误",
							content: "填写的值有误",
							type: "alert"
						});
					}
				},
				onShowed: function(dialog) {
					$('#multi_edit')
						.editable(that._selColumn.editable)
						.editable("option", "mode", "inline")
						.editable("option", "success", function(response, value) {
							successed = true;
							newValue = value;
						});
				}
			}, {
				messageType: 'confirm',
				cancel: function() {}
			});
		},

		_eraser: function() {
			var that = this;
			$.each(that._selCells, function(k, val) {
				var $el = that.$frame.find('td[id=' + val + '] a');
				var col = $el.attr('data-name');
				var row = {};
				$.each(that.data.allData, function(k, val) {
					if(val[that.options.idField] == $el.attr('data-pk')) {
						row = val;
						row[col] = "";
						return true;
					}
				});
				$el.editable('setValue', "");
				that._saveEdit(col, row, $el);
			});
		},

		_locateToError: function(id) {
			var that = this;

			if(that._curErrItem) {
				that._curErrItem.css('background-color', '');
			}

			if(!that.errors.data[id]) {
				return;
			}

			if(that.options.type == "table") {
				var pageSize = that.$table.bootstrapTable('getOptions').pageSize;
				var curPage = Math.ceil(that.errors.data[id].id / pageSize);
				that.$table.bootstrapTable('selectPage', curPage);
				that._curErrItem = that.$table.find('a[data-name="' + that.errors.data[id].col + '"][data-pk="' + that.errors.data[id].row + '"]').parents("td");
			} else if(that.options.type == "report") {
				for(var val in that.data.allData) {
					if(that.errors.data[id].id == val) {
						var curPage = Math.ceil((that.data.allData[val]['index'] + 1) / that._recordsPerPage);
						var page = that.$framepage.bootstrapPaginator('getPages');
						if(curPage != page.current) {
							that.$framepage.bootstrapPaginator('show', curPage);
							that._readReportDataPerPage(curPage);
						}
					}
				};
				that._curErrItem = that.$frame.find('td a[data-name="' + that.errors.data[id].col + '"][data-pk="' + that.errors.data[id].row + '"]').parents("td");
			}

			that._curErrItem.css('background-color', that.options.errorItemColor);
			//that.$fnLastErr.attr('disabled', (that.p_errors.data <= 0));
			//that.$fnNextErr.attr('disabled', (that.p_errors.data >= that.errors.data.length - 1));
		},

		_errlog: function() {
			var that = this;
			if(!that.errors.data.length) {
				return;
			}

			var head = [{
				"title": "顺序号",
				"width": "10%",
				"field": "id"
			}, {
				"title": "主键",
				"width": "10%",
				"field": "row"
			}, {
				"title": "字段名",
				"width": "25%",
				"field": "col"
			}, {
				"title": "字段值",
				"width": "25%",
				"field": "val"
			}, {
				"title": "错误信息",
				"width": "30%",
				"field": "msg"
			}];

			bDialog.open({
				title: '错误日志',
				width: 600,
				height: 650,
				dom: '<table id="popuptable" class="table table-condensed table-bordered"></table>',
				onShow: function(dialog) {
					$('#popuptable').bootstrapTable('destroy').bootstrapTable({
						"columns": head,
						"data": that.errors.data,
						"pagination": true,
						"showJumpto": true,
						"formatJumpto": function() {
							return '跳转';
						},
						"buttonsClass": "primary",
						"locale": 'zh_CN',
					})
				}
			})
		},

		_exportTable: function() {
			var that = this;
			if(!that.data.allData.length) {
				$.Notify({
					caption: "提示",
					content: "请先加载数据",
					type: "warning"
				});
				return;
			}
			var table = that.$table[0];
			var filename = that._tableName ? that._tableName : new Date().getTime();

			require(['xlsx', 'FileSaver'], function() {
				var exportData = [];
				$.each(that.data.allData, function(k, val) {
					var exportRow = {};
					$.each(that.columns.oriData, function(i, col) {
						if(col.visible) {
							exportRow[col.title] = val[col.title];
						}
					});
					for(var k in that.columns.colSource) {
						if(exportRow[k]) {
							exportRow[k] = that.columns.colSource[k][exportRow[k]];
						}
					};
					exportData.push(exportRow);
				});

				const wopts = {
					bookType: 'xlsx',
					bookSST: false,
					type: 'binary'
				};

				const wb = {
					SheetNames: ['Sheet1'],
					Sheets: {},
					Props: {}
				};

				wb.Sheets['Sheet1'] = XLSX.utils.json_to_sheet(exportData);

				saveAs(new Blob([s2ab(XLSX.write(wb, wopts))], {
					type: "application/octet-stream"
				}), filename + '.' + (wopts.bookType == "biff2" ? "xls" : wopts.bookType));

				function s2ab(s) {
					if(typeof ArrayBuffer !== 'undefined') {
						var buf = new ArrayBuffer(s.length);
						var view = new Uint8Array(buf);
						for(var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
						return buf;
					} else {
						var buf = new Array(s.length);
						for(var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF;
						return buf;
					}
				}
			})
		},
	}

	function openFileDialog(selectedFile, fn) {
		if(!selectedFile) {
			return;
		}
		var ext = selectedFile.name.split('.');
		if(ext[ext.length - 1] != "xls" && ext[ext.length - 1] != "xlsx" && ext[ext.length - 1] != "csv") {
			$.Notify({
				caption: "提示",
				content: "请选择Excel格式（.xls或.xlsx或.csv）的文件",
				type: "warning"
			});
			return;
		}

		var reader = new FileReader();
		reader.onload = function(e) {
			var data = e.target.result;
			var workbook = XLSX.read(data, {
				type: 'binary'
			});

			var html = $('<ul class="list-unstyled"></ul>');
			$.each(workbook.SheetNames, function(k, val) {
				var id = "p_" + k;
				html.append("<li class='selectsheet'><a href='#' onclick=bDialog.close('" + id + "');>" + val + "</a></li>");
			});

			bDialog.open({
				title: 'Sheet',
				width: 200,
				height: 300,
				dialogCloseButton: false,
				dialogMaxButton: false,
				dom: html,
				callback: function(cb) {
					if(cb && cb.results && cb.results.length > 0) {
						$("#vw-progress-text").html('正在读取本地数据，数据量较大，加载时间视数据量...');
						$("#vw-progress").removeClass('hidden');
						fn(workbook, cb.results[0].split("_")[1]);
					}
				}
			});
		};
		reader.readAsBinaryString(selectedFile);
	}

	$.fn[pluginName] = function(option) {
		var value;
		var args = Array.prototype.slice.call(arguments, 1);
		this.each(function() {
			var $this = $(this);
			var data = $this.data(pluginName);
			if(typeof option === 'string') {
				if($.inArray(option, methods) < 0) {
					throw new Error("该方法不存在: " + option);
				}
				if(!data) {
					return;
				}
				value = data[option].apply(data, args);
				if(option === 'destroy') {
					$this.removeData(pluginName);
				}
			}
			if(!data) {
				$this.data(pluginName, (data = new vw_edittable(this, option)));
			}
		});
		return typeof value === 'undefined' ? this : value;
	};
});